"""
@Author    : ghenyar
@Time      : 2025/8/28 12:32
@File      : redisCache
@Desc      : 
"""
import json
from urllib.parse import quote
from typing import Optional, Any, List
import redis.asyncio as aioredis
from redis.asyncio import Redis

from app.utils.log import LoggingUtil
from app.core.config import conf


class RedisCache:
    _redis: Optional[Redis] = None
    logger = LoggingUtil(__name__)

    @classmethod
    async def _ensure_redis(cls):
        if cls._redis is None:
            await cls.init_redis()

    @classmethod
    async def init_redis(cls):
        if cls._redis is None:
            try:
                redis_url = cls._build_redis_url()
                cls._redis = await aioredis.from_url(redis_url, decode_responses=True)
                await cls._redis.ping()
            except Exception as e:
                raise

    @classmethod
    def _build_redis_url(cls) -> str:
        password = conf.redis.password
        host = conf.redis.host
        port = conf.redis.port
        db = conf.redis.db
        if password:
            password = quote(password)
            return f"redis://:{password}@{host}:{port}/{db}"
        return f"redis://{host}:{port}/{db}"

    @classmethod
    def _get_full_key(cls, key: str) -> str:
        prefix = conf.redis.prefix
        return f"{prefix}{key}"

    @classmethod
    async def check_connection(cls) -> bool:
        await cls._ensure_redis()
        try:
            await cls._redis.ping()
            return True
        except Exception as e:
            cls.logger.warning(f"Redis 连接检查失败: {e}")
            return False

    @classmethod
    async def set(cls, key: str, value: Any, expire: Optional[int] = None):
        await cls._ensure_redis()
        try:
            full_key = cls._get_full_key(key)
            if value is None:
                await cls._redis.delete(full_key)
                return
            value_to_set = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
            await cls._redis.set(full_key, value_to_set, ex=expire)
        except Exception as e:
            cls.logger.error(f"设置 Redis 键 '{full_key}' 失败: {e}")

    @classmethod
    async def get(cls, key: str) -> Any:
        await cls._ensure_redis()
        full_key = cls._get_full_key(key)
        try:
            res_str = await cls._redis.get(full_key)
            if res_str is None:
                return None
            try:
                return json.loads(res_str)
            except json.JSONDecodeError:
                return res_str
        except Exception as e:
            cls.logger.error(f"获取 Redis 键 '{full_key}' 失败: {e}")
            return None

    @classmethod
    async def has(cls, key: str) -> bool:
        await cls._ensure_redis()
        try:
            full_key = cls._get_full_key(key)
            return await cls._redis.exists(full_key) > 0
        except Exception as e:
            cls.logger.error(f"检查 Redis 键 '{full_key}' 存在性失败: {e}")
            return False

    @classmethod
    async def delete(cls, key: str) -> int:
        await cls._ensure_redis()
        full_key = cls._get_full_key(key)
        try:
            return await cls._redis.delete(full_key)
        except Exception as e:
            cls.logger.error(f"删除 Redis 键 '{full_key}' 失败: {e}")
            return 0

    @classmethod
    async def get_ttl(cls, key: str) -> int:
        await cls._ensure_redis()
        full_key = cls._get_full_key(key)
        try:
            return await cls._redis.ttl(full_key)
        except Exception as e:
            cls.logger.error(f"获取 Redis 键 '{full_key}' TTL 失败: {e}")
            return -2

    @classmethod
    async def close(cls):
        if cls._redis:
            await cls._redis.close()
            cls._redis = None
            cls.logger.info("Redis 连接池已关闭。")

    # 可选：批量操作
    @classmethod
    async def mget(cls, keys: List[str]) -> List[Any]:
        await cls._ensure_redis()
        full_keys = [cls._get_full_key(k) for k in keys]
        try:
            results = await cls._redis.mget(full_keys)
            return [json.loads(r) if r and r.startswith(('{', '[')) else r for r in results]
        except Exception as e:
            cls.logger.error(f"批量获取 Redis 键失败: {e}")
            return []

    @classmethod
    async def mdelete(cls, keys: List[str]) -> int:
        await cls._ensure_redis()
        full_keys = [cls._get_full_key(k) for k in keys]
        try:
            return await cls._redis.delete(*full_keys)
        except Exception as e:
            cls.logger.error(f"批量删除 Redis 键失败: {e}")
            return 0
